Description: update_to_master_branch_9aug2017_1334
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 opennebula (5.4.0-1) unstable; urgency=low
 .
   * Imported from http://packages.qa.debian.org/o/opennebula.html
Author: OpenNebula Team <contact@opennebula.org>

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: http://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: <YYYY-MM-DD>

--- opennebula-5.4.0.orig/include/FedReplicaManager.h
+++ opennebula-5.4.0/include/FedReplicaManager.h
@@ -156,6 +156,11 @@ private:
      */
     pthread_mutex_t mutex;
 
+    /**
+     *  Secret to use in xmlrpc API calls
+     */
+    std::string xmlrpc_secret;
+
     // -------------------------------------------------------------------------
     // Synchronization variables
     //   - xmlrpc_timeout. To timeout xml-rpc api calls to replicate log
--- opennebula-5.4.0.orig/include/LogDB.h
+++ opennebula-5.4.0/include/LogDB.h
@@ -199,12 +199,7 @@ public:
     // -------------------------------------------------------------------------
     // Database methods
     // -------------------------------------------------------------------------
-    static int bootstrap(SqlDB *_db)
-    {
-        std::ostringstream oss(db_bootstrap);
-
-        return _db->exec_local_wr(oss);
-    }
+    static int bootstrap(SqlDB *_db);
 
     /**
      *  This function gets and initialize log related index
--- opennebula-5.4.0.orig/include/MarketPlaceAppPool.h
+++ opennebula-5.4.0/include/MarketPlaceAppPool.h
@@ -73,13 +73,14 @@ public:
      *    @param template to generate app with the from_template64 function
      *    @param mp_id of the MarketPlace to store de App
      *    @param mp_name of the MarketPlace
+     *    @param app_id of the imported app
      *    @param error_str Returns the error reason, if any
      *
      *    @return the oid assigned to the object, -1 in case of failure, -2
      *    already imported
      */
     int import(const std::string& t64, int mp_id, const std::string& mp_name,
-            std::string& error_str);
+            int& app_id, std::string& error_str);
 
     /**
      *  Function to get a MarketPlaceApp from the pool
@@ -145,6 +146,31 @@ public:
     {
         return new MarketPlaceApp(-1,-1,"","", 0, 0);
     };
+
+    /**
+     * Check an element into map
+     *   @param map_id of the app
+     *   @return true if the app has to be deleted
+     */
+    bool test_map_check(int map_id);
+
+    /**
+     *  Resets the counter of missing monitors of an app
+     *    @param app_id of the app
+     */
+    void reset_map_check(int app_id);
+
+private:
+
+    /**
+     *  Hash to store the number of times an app was missing from monitor data
+     */
+    map<int, int> map_check;
+
+    /**
+     *  Max number of monitor that an app may be missing before deleting it
+     */
+    static const int MAX_MISSING_MONITORS;
 };
 
 #endif /*MARKETPLACE_POOL_H_*/
--- opennebula-5.4.0.orig/include/RaftManager.h
+++ opennebula-5.4.0/include/RaftManager.h
@@ -292,6 +292,11 @@ private:
      */
     std::map<int, ReplicaRequest *> requests;
 
+    /**
+     *  Secret to use in xmlrpc API calls
+     */
+    std::string xmlrpc_secret;
+
     // -------------------------------------------------------------------------
     // Raft state
     // -------------------------------------------------------------------------
--- opennebula-5.4.0.orig/include/VMTemplate.h
+++ opennebula-5.4.0/include/VMTemplate.h
@@ -142,6 +142,13 @@ private:
     int insert_replace(SqlDB *db, bool replace, string& error_str);
 
     /**
+     *  Execute this method after update the template.
+     *    @param error Returns the error reason, if any
+     *    @return 0 one success
+     */
+    int post_update_template(string& error);
+
+    /**
      *  Bootstraps the database table(s) associated to the VMTemplate
      *    @return 0 on success
      */
@@ -160,6 +167,11 @@ private:
      */
     int from_xml(const string &xml_str);
 
+    /**
+     *  This method removes sched_action DONE/MESSAGE attributes
+     */
+    void parse_sched_action();
+
 protected:
 
     // *************************************************************************
--- opennebula-5.4.0.orig/share/etc/oned.conf
+++ opennebula-5.4.0/share/etc/oned.conf
@@ -157,7 +157,7 @@ RAFT = [
     LOG_PURGE_TIMEOUT    = 600,
     ELECTION_TIMEOUT_MS  = 2500,
     BROADCAST_TIMEOUT_MS = 500,
-    XMLRPC_TIMEOUT_MS    = 2000
+    XMLRPC_TIMEOUT_MS    = 0
 ]
 
 # Executed when a server transits from follower->leader
--- opennebula-5.4.0.orig/src/cli/one_helper/onehost_helper.rb
+++ opennebula-5.4.0/src/cli/one_helper/onehost_helper.rb
@@ -42,6 +42,32 @@ class OneHostHelper < OpenNebulaHelper::
                 #
                 #-----------------------------------------------------------------------
                 EOT
+        },
+        :az => {
+            :help => <<-EOT.unindent,
+                #-----------------------------------------------------------------------
+                # Supported AZURE AUTH ATTRIBUTTES:
+                #
+                #  AZ_ID   = <azure classic id>
+                #  AZ_CERT = <azure classic certificate>
+                #
+                #  REGION_NAME = <the name of the azure region>
+                #
+                #  CAPACITY = [
+                #    Small = <number of small machines>,
+                #    Medium = <number of medium machines>,
+                #    Large = <number of large machines
+                #  ]
+                #
+                # You can set any machine type supported by azure classic
+                # See your az_driver.conf for more information
+                #
+                # Optionally you can set a endpoint
+                #
+                #  AZ_ENDPOINT = <endpoint address>
+                #
+                #-----------------------------------------------------------------------
+                EOT
         }
     }
 
--- opennebula-5.4.0.orig/src/client/Client.cc
+++ opennebula-5.4.0/src/client/Client.cc
@@ -77,7 +77,7 @@ int Client::read_oneauth(string &secret,
     string   one_auth_file;
     ifstream file;
 
-    const char *  one_auth_env = getenv("ONE_AUTH");
+    const char * one_auth_env = getenv("ONE_AUTH");
 
     if (!one_auth_env) //No $ONE_AUTH, read $HOME/.one/one_auth
     {
--- opennebula-5.4.0.orig/src/host/Host.cc
+++ opennebula-5.4.0/src/host/Host.cc
@@ -693,6 +693,9 @@ int Host::from_xml(const string& xml)
     return 0;
 }
 
+/* -------------------------------------------------------------------------- */
+/* -------------------------------------------------------------------------- */
+
 static void nebula_crypt(const std::string in, std::string& out)
 {
     Nebula& nd = Nebula::instance();
@@ -715,44 +718,36 @@ static void nebula_crypt(const std::stri
     }
 }
 
+/* -------------------------------------------------------------------------- */
 
+static const map<std::string, unsigned int> MAX_HOST_VAR_SIZES = {
+    {"EC2_ACCESS", 21},
+    {"EC2_SECRET", 41},
+    {"AZ_ID", 41},
+    {"AZ_CERT", 3130},
+    {"VCENTER_PASSWORD", 22}
+};
 
 int Host::post_update_template(string& error)
 {
-    string vcenter_password;
     string new_im_mad;
     string new_vm_mad;
 
-    string ec2_access;
-    string ec2_secret;
-
-    string crypted;
-
-    get_template_attribute("VCENTER_PASSWORD", vcenter_password);
+    map<std::string, unsigned int>::const_iterator it;
 
-    if (!vcenter_password.empty() && vcenter_password.size() <= 22)
+    for (it = MAX_HOST_VAR_SIZES.begin(); it != MAX_HOST_VAR_SIZES.end() ; ++it)
     {
-        nebula_crypt(vcenter_password, crypted);
+        string att;
+        string crypted;
 
-        replace_template_attribute("VCENTER_PASSWORD", crypted);
-    }
-
-    get_template_attribute("EC2_ACCESS", ec2_access);
+        get_template_attribute(it->first.c_str(), att);
 
-    if (!ec2_access.empty() && ec2_access.size() <= 21)
-    {
-        nebula_crypt(ec2_access, crypted);
-
-        replace_template_attribute("EC2_ACCESS", crypted);
-    }
-
-    get_template_attribute("EC2_SECRET", ec2_secret);
-
-    if (!ec2_secret.empty() && ec2_secret.size() <= 41)
-    {
-        nebula_crypt(ec2_secret, crypted);
+        if (!att.empty() && att.size() <= it->second)
+        {
+            nebula_crypt(att, crypted);
 
-        replace_template_attribute("EC2_SECRET", crypted);
+            replace_template_attribute(it->first, crypted);
+        }
     }
 
     get_template_attribute("IM_MAD", new_im_mad);
--- opennebula-5.4.0.orig/src/market/MarketPlaceAppPool.cc
+++ opennebula-5.4.0/src/market/MarketPlaceAppPool.cc
@@ -190,7 +190,7 @@ int MarketPlaceAppPool::drop(PoolObjectS
 /* -------------------------------------------------------------------------- */
 
 int MarketPlaceAppPool::import(const std::string& t64, int mp_id,
-        const std::string& mp_name, std::string& error_str)
+        const std::string& mp_name, int& app_id, std::string& error_str)
 {
     // -------------------------------------------------------------------------
     // Build the marketplace app object
@@ -229,6 +229,8 @@ int MarketPlaceAppPool::import(const std
 
     if( mp_aux != 0 ) //Marketplace app already imported
     {
+        app_id = mp_aux->oid;
+
         if ( mp_aux->version != app->version || mp_aux->md5 != app->md5 )
         {
             mp_aux->from_template64(t64, error_str);
@@ -248,15 +250,17 @@ int MarketPlaceAppPool::import(const std
     // -------------------------------------------------------------------------
     if (Nebula::instance().is_federation_slave())
     {
-        int oid = master_allocate(app, error_str);
+        app_id = master_allocate(app, error_str);
 
         app->lock();
         delete app;
 
-        return oid;
+        return app_id;
     }
 
-    return PoolSQL::allocate(app, error_str);
+    app_id = PoolSQL::allocate(app, error_str);
+
+    return app_id;
 }
 
 /* -------------------------------------------------------------------------- */
@@ -308,4 +312,39 @@ int MarketPlaceAppPool::update(PoolObjec
 
 /* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
+const int MarketPlaceAppPool::MAX_MISSING_MONITORS = 3;
+
+bool MarketPlaceAppPool::test_map_check(int app_id)
+{
+    map<int, int>::iterator it = map_check.find(app_id);
 
+    if ( it == map_check.end() )
+    {
+        return false;
+    }
+
+    it->second++;
+
+    bool to_delete = it->second >= MAX_MISSING_MONITORS;
+
+    if ( to_delete )
+    {
+        map_check.erase(it); 
+    }
+
+    return to_delete;
+}
+
+void MarketPlaceAppPool::reset_map_check(int app_id)
+{
+    map<int, int>::iterator it = map_check.find(app_id);
+
+    if ( it == map_check.end() )
+    {
+        map_check.insert(make_pair(app_id, -1));
+    }
+    else
+    {
+        it->second = -1;
+    }
+}
--- opennebula-5.4.0.orig/src/market/MarketPlaceManagerDriver.cc
+++ opennebula-5.4.0/src/market/MarketPlaceManagerDriver.cc
@@ -120,7 +120,6 @@ static void monitor_action(
         return;
     }
 
-    std::string   name;
     MarketPlace * market = marketpool->get(id, true);
 
     if (market == 0 )
@@ -128,7 +127,8 @@ static void monitor_action(
         return;
     }
 
-    name    = market->get_name();
+    set<int> apps_mp = market->get_marketapp_ids();
+    std::string name = market->get_name();
 
     market->update_monitor(monitor_data);
 
@@ -143,7 +143,8 @@ static void monitor_action(
 
     for (int i=0; i< num ; i++)
     {
-        int rc = apppool->import(apps[i]->value(), id, name, err);
+        int app_id;
+        int rc = apppool->import(apps[i]->value(), id, name, app_id, err);
 
         if ( rc == -1 )
         {
@@ -162,6 +163,37 @@ static void monitor_action(
                 market->unlock();
             }
         }
+
+        apppool->reset_map_check(app_id);
+
+        apps_mp.erase(app_id);
+    }
+
+    for (set<int>::iterator i = apps_mp.begin(); i != apps_mp.end(); ++i)
+    {
+        if (apppool->test_map_check(*i)) //delete app
+        { 
+            std::string error;
+
+            MarketPlaceApp * app = apppool->get(*i, true);
+
+            if ( app == 0 )
+            {
+                continue;
+            }
+
+            rc = apppool->drop(app, error);
+
+            app->unlock();
+
+            market = marketpool->get(id, true);
+
+            market->del_marketapp(*i);
+
+            marketpool->update(market);
+
+            market->unlock();
+        }
     }
 
     oss << "Marketplace " << name << " (" << id << ") successfully monitored.";
--- opennebula-5.4.0.orig/src/onedb/fsck.rb
+++ opennebula-5.4.0/src/onedb/fsck.rb
@@ -568,15 +568,16 @@ EOT
     # Params:
     # +type+:: type name of the disk, can be “hd” or “cdrom”
     # +doc+:: Nokogiri::XML::Node describing the VM template
-    def get_disk_id(type, index, doc)
+    def get_disk_id(type, index, doc, uid)
         found_i = -1
 
         doc.root.xpath("TEMPLATE/DISK").each_with_index do |disk, disk_i|
             id = disk.at_xpath("IMAGE_ID")
-            if ! id.nil?
+
+            if id
                 image = get_image_from_id(id.content)
             else
-                image = get_image_from_name(disk)
+                image = get_image_from_name(disk, uid)
             end
 
             next if image.nil?
@@ -608,29 +609,34 @@ EOT
     # Returns a Nokogiri::XML::Node describing an image
     # Params:
     # +disk+:: Nokogiri::XML::Node describing a disk used by a template
-    def get_image_from_name(disk)
-      name = disk.at_xpath("IMAGE") && disk.at_xpath("IMAGE").content
-      uid = disk.at_xpath("IMAGE_UID")
-      uname = disk.at_xpath("IMAGE_UNAME")
-
-      if ! name.nil? and (! uid.nil? or ! uname.nil?)
-        if uid.nil?
-          uid = get_user_id(uname.content)
+    def get_image_from_name(disk, template_uid)
+        name = disk.at_xpath("IMAGE") && disk.at_xpath("IMAGE").content
+
+        return nil if name.nil?
+
+        uid   = disk.at_xpath("IMAGE_UID")
+        uname = disk.at_xpath("IMAGE_UNAME")
+
+        if uid
+            uid = uid.content
         else
-          uid = uid.content
+            if uname
+                uid = get_user_id(uname.content)
+            else
+                uid = template_uid
+            end
         end
 
         return nil if uid.nil?
 
-        row = @db.fetch("SELECT body from image_pool where name=\"#{name}\" and uid=#{uid}").first
+        row = @db.fetch("SELECT body FROM image_pool WHERE name=\"#{name}\" AND uid=#{uid}").first
+
         # No image found, so unable to get image TYPE
         return nil if row.nil?
 
         image = Nokogiri::XML(row[:body], nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks}
-        return image
-      end
 
-      return nil
+        return image
     end
 
     # Returns the ID of a user name
--- opennebula-5.4.0.orig/src/onedb/fsck/marketplace.rb
+++ opennebula-5.4.0/src/onedb/fsck/marketplace.rb
@@ -82,7 +82,7 @@ module OneDBFsck
                     @db[:marketplace_pool].where(:oid => id).update(:body => body)
                 end
             end
-        elsif !markets_fix.empty?
+        elsif !@fixes_marketplace.empty?
             log_msg("^ Marketplace errors need to be fixed in the master OpenNebula")
         end
     end
--- opennebula-5.4.0.orig/src/onedb/fsck/marketplaceapp.rb
+++ opennebula-5.4.0/src/onedb/fsck/marketplaceapp.rb
@@ -78,7 +78,7 @@ module OneDBFsck
                     @db[:marketplaceapp_pool].where(:oid => id).update(:body => body)
                 end
             end
-        elsif !apps_fix.empty?
+        elsif !@fixes_marketplaceapp.empty?
             log_msg("^ Marketplace App errors need to be fixed in the master OpenNebula")
         end
     end
--- opennebula-5.4.0.orig/src/onedb/fsck/template.rb
+++ opennebula-5.4.0/src/onedb/fsck/template.rb
@@ -8,6 +8,8 @@ module OneDBFsck
 
             boot = doc.root.at_xpath("TEMPLATE/OS/BOOT")
 
+            uid = doc.root.at_xpath('UID').content
+
             if boot.nil? || boot.text.downcase.match(/fd|hd|cdrom|network/).nil?
                 next
             end
@@ -40,7 +42,8 @@ module OneDBFsck
                         cdrom_i += 1
                     end
 
-                    id = get_disk_id(dev, index, doc)
+                    id = get_disk_id(dev, index, doc, uid)
+
                     if id.nil?
                         log_error("VM Template #{row[:oid]} OS/BOOT contains deprecated format \"#{boot.content}\", but DISK ##{index} of type #{dev} could not be found to fix it automatically", false)
                         error = true
--- opennebula-5.4.0.orig/src/raft/FedReplicaManager.cc
+++ opennebula-5.4.0/src/raft/FedReplicaManager.cc
@@ -29,9 +29,16 @@ const time_t FedReplicaManager::xmlrpc_t
 
 FedReplicaManager::FedReplicaManager(LogDB * d): ReplicaManager(), logdb(d)
 {
+    std::string error;
+
     pthread_mutex_init(&mutex, 0);
 
     am.addListener(this);
+
+    if ( Client::read_oneauth(xmlrpc_secret, error) == -1 )
+    {
+        throw runtime_error(error);
+    }
 };
 
 /* -------------------------------------------------------------------------- */
@@ -391,7 +398,7 @@ int FedReplicaManager::xmlrpc_replicate_
 {
     static const std::string replica_method = "one.zone.fedreplicate";
 
-    std::string secret, zedp;
+    std::string zedp;
 
 	int xml_rc = 0;
 
@@ -407,15 +414,10 @@ int FedReplicaManager::xmlrpc_replicate_
     // -------------------------------------------------------------------------
     // Get parameters to call append entries on follower
     // -------------------------------------------------------------------------
-    if ( Client::read_oneauth(secret, error) == -1 )
-    {
-        return -1;
-    }
-
     xmlrpc_c::value result;
     xmlrpc_c::paramList replica_params;
 
-    replica_params.add(xmlrpc_c::value_string(secret));
+    replica_params.add(xmlrpc_c::value_string(xmlrpc_secret));
     replica_params.add(xmlrpc_c::value_int(lr.index));
     replica_params.add(xmlrpc_c::value_int(prev_index));
     replica_params.add(xmlrpc_c::value_string(lr.sql));
--- opennebula-5.4.0.orig/src/raft/RaftManager.cc
+++ opennebula-5.4.0/src/raft/RaftManager.cc
@@ -54,12 +54,17 @@ RaftManager::RaftManager(int id, const V
     Nebula& nd    = Nebula::instance();
     LogDB * logdb = nd.get_logdb();
 
-    std::string raft_xml, cmd, arg;
+    std::string raft_xml, cmd, arg, error;
 
 	pthread_mutex_init(&mutex, 0);
 
 	am.addListener(this);
 
+    if ( Client::read_oneauth(xmlrpc_secret, error) == -1 )
+    {
+        throw runtime_error(error);
+    }
+
     // -------------------------------------------------------------------------
     // Initialize Raft variables:
     //   - state
@@ -481,17 +486,19 @@ void RaftManager::follower(unsigned int
 
     state = FOLLOWER;
 
-    term     = _term;
-    votedfor = -1;
-
-    commit   = lapplied;
+    if ( _term > term )
+    {
+        term     = _term;
+        votedfor = -1;
 
-    leader_id = -1;
+        raft_state.replace("VOTEDFOR", votedfor);
+        raft_state.replace("TERM", term);
 
-    raft_state.replace("VOTEDFOR", votedfor);
-    raft_state.replace("TERM", term);
+        raft_state.to_xml(raft_state_xml);
+    }
 
-    raft_state.to_xml(raft_state_xml);
+    commit    = lapplied;
+    leader_id = -1;
 
     NebulaLog::log("RCM", Log::INFO, "oned is set to follower mode");
 
@@ -518,7 +525,10 @@ void RaftManager::follower(unsigned int
         frm->stop_replica_threads();
     }
 
-    logdb->update_raft_state(raft_state_xml);
+    if (!raft_state_xml.empty())
+    {
+        logdb->update_raft_state(raft_state_xml);
+    }
 }
 
 /* -------------------------------------------------------------------------- */
@@ -982,7 +992,6 @@ int RaftManager::xmlrpc_replicate_log(in
 
     static const std::string replica_method = "one.zone.replicate";
 
-    std::string secret;
     std::string follower_edp;
 
     std::map<int, std::string>::iterator it;
@@ -1012,16 +1021,10 @@ int RaftManager::xmlrpc_replicate_log(in
     // -------------------------------------------------------------------------
     // Get parameters to call append entries on follower
     // -------------------------------------------------------------------------
-    if ( Client::read_oneauth(secret, error) == -1 )
-    {
-        NebulaLog::log("RRM", Log::ERROR, error);
-        return -1;
-    }
-
     xmlrpc_c::value result;
     xmlrpc_c::paramList replica_params;
 
-    replica_params.add(xmlrpc_c::value_string(secret));
+    replica_params.add(xmlrpc_c::value_string(xmlrpc_secret));
     replica_params.add(xmlrpc_c::value_int(_server_id));
     replica_params.add(xmlrpc_c::value_int(_commit));
     replica_params.add(xmlrpc_c::value_int(_term));
@@ -1080,7 +1083,6 @@ int RaftManager::xmlrpc_request_vote(int
 
     static const std::string replica_method = "one.zone.voterequest";
 
-    std::string secret;
     std::string follower_edp;
 
     std::map<int, std::string>::iterator it;
@@ -1109,16 +1111,10 @@ int RaftManager::xmlrpc_request_vote(int
     // -------------------------------------------------------------------------
     // Get parameters to call append entries on follower
     // -------------------------------------------------------------------------
-    if ( Client::read_oneauth(secret, error) == -1 )
-    {
-        NebulaLog::log("RRM", Log::ERROR, error);
-        return -1;
-    }
-
     xmlrpc_c::value result;
     xmlrpc_c::paramList replica_params;
 
-    replica_params.add(xmlrpc_c::value_string(secret));
+    replica_params.add(xmlrpc_c::value_string(xmlrpc_secret));
     replica_params.add(xmlrpc_c::value_int(_term));
     replica_params.add(xmlrpc_c::value_int(_server_id));
     replica_params.add(xmlrpc_c::value_int(lindex));
--- opennebula-5.4.0.orig/src/sql/LogDB.cc
+++ opennebula-5.4.0/src/sql/LogDB.cc
@@ -32,6 +32,28 @@ const char * LogDB::db_bootstrap = "CREA
     "timestamp INTEGER, fed_index INTEGER)";
 
 /* -------------------------------------------------------------------------- */
+
+int LogDB::bootstrap(SqlDB *_db)
+{
+    int rc;
+
+    std::ostringstream oss(db_bootstrap);
+
+    rc = _db->exec_local_wr(oss);
+
+    // Create indexes
+    oss.str("CREATE INDEX fed_index_idx on logdb (fed_index);");
+
+    rc += _db->exec_local_wr(oss);
+
+    oss.str("CREATE INDEX timestamp_idx on logdb (timestamp);");
+
+    rc += _db->exec_local_wr(oss);
+
+    return rc;
+};
+
+/* -------------------------------------------------------------------------- */
 /* -------------------------------------------------------------------------- */
 
 int LogDBRecord::select_cb(void *nil, int num, char **values, char **names)
@@ -199,14 +221,6 @@ int LogDB::get_log_record(unsigned int i
 
     if ( lr.index != index )
     {
-        std::ostringstream oss;
-
-        oss << "Log record " << index << " loaded incorrectly. Record index: "
-            << lr.index << " fed. index: " << lr.fed_index << " sql command: " 
-            << lr.sql << ". Operation return code: " << rc;
-
-        NebulaLog::log("DBM", Log::ERROR, oss);
-
         rc = -1;
     }
 
--- opennebula-5.4.0.orig/src/sunstone/etc/sunstone-views/admin.yaml
+++ opennebula-5.4.0/src/sunstone/etc/sunstone-views/admin.yaml
@@ -56,6 +56,12 @@ features:
     # True to show the option to make an instance persistent
     instantiate_persistent: true
 
+    # True to show the datastore datatable to instantiate VM
+    show_ds_instantiate: true
+
+    # True to show the host datatable to instantiate VM
+    show_host_instantiate: true
+
     # True to show an input to specify the the VMs and Template path/folder where a vCenter VM will
     # deployed to
     vcenter_vm_folder: false
@@ -226,6 +232,7 @@ tabs:
             features: true
             input_output: true
             context: true
+            actions: true
             scheduling: true
             hybrid: true
             vmgroup: true
--- opennebula-5.4.0.orig/src/sunstone/etc/sunstone-views/admin_vcenter.yaml
+++ opennebula-5.4.0/src/sunstone/etc/sunstone-views/admin_vcenter.yaml
@@ -56,6 +56,12 @@ features:
     # True to show the option to make an instance persistent
     instantiate_persistent: true
 
+    # True to show the datastore datatable to instantiate VM
+    show_ds_instantiate: false
+
+    # True to show the host datatable to instantiate VM
+    show_host_instantiate: false
+
     # True to show an input to specify the the VMs and Template path/folder where a vCenter VM will
     # deployed to
     vcenter_vm_folder: true
@@ -224,6 +230,7 @@ tabs:
             features: true
             input_output: true
             context: true
+            actions: true
             scheduling: true
             hybrid: true
             vmgroup: true
--- opennebula-5.4.0.orig/src/sunstone/etc/sunstone-views/cloud.yaml
+++ opennebula-5.4.0/src/sunstone/etc/sunstone-views/cloud.yaml
@@ -88,6 +88,8 @@ tabs:
             vmgroup_select: true
             # True to allow DISK size customization
             disk_resize: true
+            # True to allow datastore customization
+            datastore_select: true
     settings-tab:
         panel_tabs:
             settings_info_tab: false
@@ -153,4 +155,20 @@ tabs:
             - 4         # Owner
             - 5         # Vms
             #- 6         # Labels
-            #- 7        # Search data
\ No newline at end of file
+            #- 7        # Search data
+    datastores-tab:
+        table_columns:
+            - 0         # Checkbox
+            - 1         # ID
+            - 2         # Owner
+            - 3         # Group
+            - 4         # Name
+            #- 5         # Capacity
+            #- 6         # Cluster
+            #- 7         # Basepath
+            #- 8         # TM
+            #- 9         # DS
+            #- 10        # Type
+            - 11        # Status
+            #- 12        # Labels
+            #- 13        # Search data
\ No newline at end of file
--- opennebula-5.4.0.orig/src/sunstone/etc/sunstone-views/cloud_vcenter.yaml
+++ opennebula-5.4.0/src/sunstone/etc/sunstone-views/cloud_vcenter.yaml
@@ -85,7 +85,7 @@ tabs:
             # True to allow NIC customization
             network_select: true
             # True to allow DISK size customization
-            disk_resize: false
+            disk_resize: true
     settings-tab:
         panel_tabs:
             settings_info_tab: false
--- opennebula-5.4.0.orig/src/sunstone/etc/sunstone-views/groupadmin.yaml
+++ opennebula-5.4.0/src/sunstone/etc/sunstone-views/groupadmin.yaml
@@ -56,6 +56,12 @@ features:
     # True to show the option to make an instance persistent
     instantiate_persistent: true
 
+    # True to show the datastore datatable to instantiate VM
+    show_ds_instantiate: false
+
+    # True to show the host datatable to instantiate VM
+    show_host_instantiate: false
+
     # True to show an input to specify the the VMs and Template path/folder where a vCenter VM will
     # deployed to
     vcenter_vm_folder: false
@@ -225,6 +231,7 @@ tabs:
             features: true
             input_output: true
             context: true
+            actions: true
             scheduling: true
             hybrid: true
             vmgroup: true
--- opennebula-5.4.0.orig/src/sunstone/etc/sunstone-views/groupadmin_vcenter.yaml
+++ opennebula-5.4.0/src/sunstone/etc/sunstone-views/groupadmin_vcenter.yaml
@@ -225,6 +225,7 @@ tabs:
             features: true
             input_output: true
             context: true
+            actions: true
             scheduling: true
             hybrid: true
             vmgroup: true
--- opennebula-5.4.0.orig/src/sunstone/etc/sunstone-views/user.yaml
+++ opennebula-5.4.0/src/sunstone/etc/sunstone-views/user.yaml
@@ -56,6 +56,12 @@ features:
     # True to show the option to make an instance persistent
     instantiate_persistent: true
 
+    # True to show the datastore datatable to instantiate VM
+    show_ds_instantiate: false
+
+    # True to show the host datatable to instantiate VM
+    show_host_instantiate: false
+
     # True to show an input to specify the the VMs and Template path/folder where a vCenter VM will
     # deployed to
     vcenter_vm_folder: false
@@ -224,6 +230,7 @@ tabs:
             features: true
             input_output: true
             context: true
+            actions: true
             scheduling: false
             hybrid: true
             vmgroup: true
--- opennebula-5.4.0.orig/src/sunstone/public/app/app.js
+++ opennebula-5.4.0/src/sunstone/public/app/app.js
@@ -294,6 +294,33 @@ define(function(require) {
       }
     }
 
+    jQuery.extend( jQuery.fn.dataTableExt.oSort, {
+      "date-euro-pre": function ( a ) {
+          var x;
+
+          if ( $.trim(a) !== '' ) {
+              var frDatea = $.trim(a).split(' ');
+              var frTimea = (undefined != frDatea[1]) ? frDatea[1].split(':') : [00,00,00];
+              var frDatea2 = frDatea[0].split('/');
+              x = (frDatea2[2] + frDatea2[1] + frDatea2[0] + frTimea[0] + frTimea[1] + ((undefined != frTimea[2]) ? frTimea[2] : 0)) * 1;
+          }
+          else {
+              x = Infinity;
+          }
+
+          return x;
+      },
+
+      "date-euro-asc": function ( a, b ) {
+          return a - b;
+      },
+
+      "date-euro-desc": function ( a, b ) {
+          return b - a;
+      }
+
+    });
+
     //source https://cdn.datatables.net/plug-ins/1.10.12/type-detection/ip-address.js (modified)
     jQuery.fn.dataTableExt.aTypes.unshift(
       function ( sData )
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/acls-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/acls-tab.js
@@ -40,7 +40,9 @@ define(function(require) {
     tabClass: "subTab",
     parentTab: "system-top-tab",
     listHeader: Locale.tr("Access Control Lists"),
-    subheader: '<span/><small></small>&emsp;',
+    subheader: '<span>\
+        <span class="total_acl"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'Acl',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/acls-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/acls-tab/datatable.js
@@ -57,6 +57,8 @@ define(function(require) {
       ]
     };
 
+    this.totalACLs = 0;
+
     this.columns = [
       Locale.tr("ID"),
       Locale.tr("Applies to"),
@@ -82,6 +84,8 @@ define(function(require) {
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -96,6 +100,8 @@ define(function(require) {
 
     var acl_array = _parseAclString(acl_string);
 
+    this.totalACLs++;
+
     return [
       '<input class="check_item" type="checkbox" id="'+RESOURCE.toLowerCase()+'_' +
                            element.ID + '" name="selected_items" value="' +
@@ -264,4 +270,12 @@ define(function(require) {
     return zone_str;
   }
 
+  function _preUpdateView() {
+    this.totalACLs = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_acl").text(this.totalACLs);
+  }
+
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/clusters-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/clusters-tab.js
@@ -49,7 +49,9 @@ define(function(require) {
     parentTab: "infrastructure-top-tab",
     listHeader: Locale.tr("Clusters"),
     infoHeader: Locale.tr("Cluster"),
-    subheader: '<span/> <small></small>&emsp;',
+    subheader: '<span>\
+        <span class="total_clusters"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'Cluster',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/clusters-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/clusters-tab/datatable.js
@@ -76,12 +76,16 @@ define(function(require) {
       "you_selected_multiple": Locale.tr("You selected the following clusters:")
     };
 
+    this.totalClusters = 0;
+
     TabDataTable.call(this);
   }
 
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -91,6 +95,7 @@ define(function(require) {
 
   function _elementArray(element_json) {
     var element = element_json[XML_ROOT];
+    this.totalClusters++;
 
     return [
       '<input class="check_item" type="checkbox" id="'+RESOURCE.toLowerCase()+'_' +
@@ -114,4 +119,13 @@ define(function(require) {
 
     return l;
   }
+
+  function _preUpdateView() {
+    this.totalClusters = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_clusters").text(this.totalClusters);
+  }
+
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/datastores-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/datastores-tab.js
@@ -49,7 +49,9 @@ define(function(require) {
     parentTab: "storage-top-tab",
     listHeader: Locale.tr("Datastores"),
     infoHeader: Locale.tr("Datastore"),
-    subheader: '',
+    subheader: '<span class="total_ds"/> <small>'+Locale.tr("TOTAL")+'</small>&emsp;\
+        <span class="total_on"/> <small>'+Locale.tr("ON")+'</small>&emsp;\
+        <span class="total_off"/> <small>'+Locale.tr("OFF")+'</small>',
     resource: 'Datastore',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/datastores-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/datastores-tab/datatable.js
@@ -106,12 +106,18 @@ define(function(require) {
     this.conf.searchDropdownHTML = SearchDropdown({tableId: this.dataTableId});
     this.searchColumn = SEARCH_COLUMN;
 
+    this.totalDSs = 0;
+    this.totalON = 0;
+    this.totalOFF = 0;
+
     TabDataTable.call(this);
   };
 
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -121,6 +127,7 @@ define(function(require) {
 
   function _elementArray(element_json) {
     var element = element_json.DATASTORE;
+    this.totalDSs++;
 
     var clusters = '-';
     if (element.CLUSTERS.ID != undefined){
@@ -129,6 +136,12 @@ define(function(require) {
 
     var state = OpenNebulaDatastore.stateStr(element.STATE);
 
+    if(state == "ON"){
+      this.totalON++;
+    } else if(state == "OFF"){
+      this.totalOFF++;
+    }
+
     var search = {
       NAME:   element.NAME,
       UNAME:  element.UNAME,
@@ -157,4 +170,16 @@ define(function(require) {
         btoa(unescape(encodeURIComponent(JSON.stringify(search))))
     ];
   }
+
+  function _preUpdateView() {
+    this.totalDSs = 0;
+    this.totalON = 0;
+    this.totalOFF = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_ds").text(this.totalDSs);
+    $(".total_on").text(this.totalON);
+    $(".total_off").text(this.totalOFF);
+  }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/files-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/files-tab.js
@@ -45,7 +45,9 @@ define(function(require) {
     parentTab: "storage-top-tab",
     listHeader: Locale.tr("Files"),
     infoHeader: Locale.tr("File"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_files"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'File',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/files-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/files-tab/datatable.js
@@ -47,12 +47,15 @@ define(function(require) {
       "you_selected_multiple": Locale.tr("You selected the following files:")
     };
 
+    this.totalFiles = 0;
     ImageCommonDataTable.call(this, RESOURCE, TAB_NAME, dataTableId, conf);
   };
 
   Table.prototype = Object.create(ImageCommonDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -69,6 +72,15 @@ define(function(require) {
       return false;
     }
 
+    this.totalFiles++;
     return this.elementArrayCommon(element_json);
   }
+
+  function _preUpdateView() {
+    this.totalFiles = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_files").text(this.totalFiles);
+  }
 });
\ No newline at end of file
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/images-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/images-tab.js
@@ -50,7 +50,8 @@ define(function(require) {
     parentTab: "storage-top-tab",
     listHeader: Locale.tr("Images"),
     infoHeader: Locale.tr("Image"),
-    subheader: '',
+    subheader: '<span class="total_images"/> <small>'+Locale.tr("TOTAL")+'</small>&emsp;\
+        <span class="size_images"/> <small>'+Locale.tr("TOTAL SIZE")+'</small>',
     resource: 'Image',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/marketplaceapps-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/marketplaceapps-tab.js
@@ -52,7 +52,9 @@ define(function(require) {
     parentTab: "storage-top-tab",
     listHeader: Locale.tr("Apps"),
     infoHeader: Locale.tr("App"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_apps"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'MarketPlaceApp',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/marketplaceapps-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/marketplaceapps-tab/datatable.js
@@ -75,7 +75,8 @@ define(function(require) {
           {"sWidth": "35px", "aTargets": [0]},
           {"bVisible": true, "aTargets": SunstoneConfig.tabTableColumns(TAB_NAME)},
           {"bVisible": false, "aTargets": ['_all']},
-          {"sType": "file-size", "aTargets": [ 6 ] }
+          {"sType": "file-size", "aTargets": [ 6 ]},
+          {"sType": "date-euro", "aTargets": [ 9 ]}
       ]
     }
 
@@ -105,6 +106,8 @@ define(function(require) {
       "you_selected_multiple": Locale.tr("You selected the following appliances:")
     }
 
+    this.totalApps = 0;
+
     this.conf.searchDropdownHTML = SearchDropdown({tableId: this.dataTableId});
     this.searchColumn = SEARCH_COLUMN;
 
@@ -114,6 +117,8 @@ define(function(require) {
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -127,6 +132,8 @@ define(function(require) {
     var state = OpenNebulaMarketPlaceApp.stateStr(element.STATE);
     var zone = OpenNebulaZone.getName(element.ZONE_ID);
 
+    this.totalApps++;
+
     var search = {
       NAME:           element.NAME,
       UNAME:          element.UNAME,
@@ -150,7 +157,7 @@ define(function(require) {
         Humanize.sizeFromMB(element.SIZE),
         state,
         OpenNebulaMarketPlaceApp.typeStr(element.TYPE),
-        Humanize.prettyTime(element.REGTIME),
+        Humanize.prettyTimeDatatable(element.REGTIME),
         element.MARKETPLACE,
         zone,
         (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||''),
@@ -167,4 +174,12 @@ define(function(require) {
 
     return l;
   }
+
+  function _preUpdateView() {
+    this.totalApps = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_apps").text(this.totalApps);
+  }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/marketplaces-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/marketplaces-tab.js
@@ -51,7 +51,9 @@ define(function(require) {
     parentTab: "storage-top-tab",
     listHeader: Locale.tr("MarketPlaces"),
     infoHeader: Locale.tr("MarketPlace"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_markets"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'MarketPlace',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/marketplaces-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/marketplaces-tab/datatable.js
@@ -104,12 +104,16 @@ define(function(require) {
     this.conf.searchDropdownHTML = SearchDropdown({tableId: this.dataTableId});
     this.searchColumn = SEARCH_COLUMN;
 
+    this.totalMarkets = 0;
+
     TabDataTable.call(this);
   };
 
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -119,6 +123,7 @@ define(function(require) {
 
   function _elementArray(element_json) {
     var element = element_json[XML_ROOT];
+    this.totalMarkets++;
 
     var zone = OpenNebulaZone.getName(element.ZONE_ID);
 
@@ -156,4 +161,12 @@ define(function(require) {
 
     return l;
   }
+
+  function _preUpdateView() {
+    this.totalMarkets = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_markets").text(this.totalMarkets);
+  }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/provision-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/provision-tab.js
@@ -40,6 +40,8 @@ define(function(require) {
   var UserInputs = require('utils/user-inputs');
   var CapacityInputs = require('tabs/templates-tab/form-panels/create/wizard-tabs/general/capacity-inputs');
   var LabelsUtils = require('utils/labels/utils');
+  var DatastoresTable = require('tabs/datastores-tab/datatable');
+  var UniqueId = require('utils/unique-id');
 
   var ProvisionVmsList = require('./provision-tab/vms/list');
   var ProvisionTemplatesList = require('./provision-tab/templates/list');
@@ -92,6 +94,7 @@ define(function(require) {
     $("#vm_name", context).val('');
     $(".provision_selected_networks").html("");
     $(".provision_vmgroup_selector").html("");
+    $(".provision_ds_selector").html("");
     $(".provision-pricing-table", context).removeClass("selected");
     $(".alert-box-error", context).hide();
     $(".total_cost_div", context).hide();
@@ -569,8 +572,10 @@ define(function(require) {
     $("#provision_create_vm .provision_disk_selector").removeData("template_json");
     $("#provision_create_vm .provision_network_selector").html("");
     $("#provision_create_vm .provision_vmgroup_selector").html("");
+    $("#provision_create_vm .provision_ds_selector").html("");
     $("#provision_create_vm .provision_add_vmgroup").show();
     $("#provision_create_vm .provision_vmgroup").hide();
+    $("#provision_create_vm .provision_ds").hide();
 
     $("#provision_create_vm .provision_custom_attributes_selector").html("")
 
@@ -595,12 +600,13 @@ define(function(require) {
     $(".provision_vmgroup_selector", context).html("");
     $(".provision_add_vmgroup", context).show();
     $(".provision_vmgroup", context).hide();
+    //$(".provision_ds", context).hide();
     $(".provision_custom_attributes_selector", context).html("");
 
     $(".provision_accordion_flow_template .selected_template", context).hide();
     $(".provision_accordion_flow_template .select_template", context).show();
 
-    $("li:not(.is-active) a[href='#provision_dd_flow_template']", context).trigger("click")
+    $("li:not(.is-active) a[href='#provision_dd_flow_template']", context).trigger("click");
 
     $(".total_cost_div", context).hide();
     $(".alert-box-error", context).hide();
@@ -946,6 +952,7 @@ define(function(require) {
             $(".provision_accordion_template a").first().trigger("click");
 
             $("#provision_create_vm .provision_vmgroup").show();
+            $("#provision_create_vm .provision_ds").show();
             OpenNebula.Template.show({
               data : {
                 id: template_id,
@@ -983,11 +990,45 @@ define(function(require) {
                 }
 
                 if (Config.provision.create_vm.isEnabled("vmgroup_select")) {
+                  $(".provision_vmgroup_selector", create_vm_context).html("");
+                  $("#provision_create_vm .provision_add_vmgroup").show();
                   VMGroupSection.insert(template_json, $(".vmgroupContext", create_vm_context));
                 } else {
                   $(".provision_vmgroup_selector", create_vm_context).html("");
                 }
 
+                if (Config.provision.create_vm.isEnabled("datastore_select")) {
+                  $(".provision_ds_selector", create_vm_context).html("");
+                  var options = {
+                    'select': true,
+                    'selectOptions': {
+                      'multiple_choice': true
+                    }
+                  }
+                  this.datastoresTable = new DatastoresTable('DatastoresTable' + UniqueId.id(), options);
+                  $(".provision_ds_selector", create_vm_context).html(this.datastoresTable.dataTableHTML);
+                  this.datastoresTable.initialize();
+                  this.datastoresTable.filter("system", 10);
+                  this.datastoresTable.refreshResourceTableSelect();
+                  if(template_json.VMTEMPLATE.TEMPLATE.SCHED_DS_REQUIREMENTS){
+                    var dsReqJSON = template_json.VMTEMPLATE.TEMPLATE.SCHED_DS_REQUIREMENTS;
+                    var dsReq = TemplateUtils.escapeDoubleQuotes(dsReqJSON);
+                    var ds_id_regexp = /(\s|\||\b)ID=\\"([0-9]+)\\"/g;
+                    var ds = [];
+                    while (match = ds_id_regexp.exec(dsReq)) {
+                      ds.push(match[2]);
+                    }
+                    var selectedResources = {
+                      ids : ds
+                    }
+                    this.datastoresTable.selectResourceTableSelect(selectedResources);
+                    $(".provision_ds_selector", create_vm_context).data("dsTable", this.datastoresTable);
+                  }
+                } else {
+                  $(".provision_ds_selector", create_vm_context).html("");
+                  $(".provision_ds", create_vm_context).hide();
+                }
+
                 if (template_json.VMTEMPLATE.TEMPLATE.USER_INPUTS) {
                   UserInputs.vmTemplateInsert(
                       $(".provision_custom_attributes_selector", create_vm_context),
@@ -1044,6 +1085,20 @@ define(function(require) {
             $.extend(extra_info.template, vmgroup);
           }
 
+          var dsTable = $(".provision_ds_selector", context).data("dsTable");
+          if(dsTable != undefined){
+            var req_string = [];
+            var ds = dsTable.retrieveResourceTableSelect();
+            if(ds){
+              $.each(ds, function(index, dsId) {
+                req_string.push('ID="' + dsId + '"');
+              });
+              req_string = req_string.join(" | ");
+              req_string = TemplateUtils.escapeDoubleQuotes(req_string);
+              extra_info.template.SCHED_DS_REQUIREMENTS = req_string;
+            }
+          }
+
           if (nics.length > 0) {
             extra_info.template.nic = nics;
           }
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/provision-tab/vms/create.hbs
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/provision-tab/vms/create.hbs
@@ -140,4 +140,14 @@
       </fieldset>
     </div>
   </div>
+  <div class="row provision_ds" hidden="true">
+    <div class="small-12 columns dsContext{{element.ID}}">
+      <fieldset>
+        <legend>
+          <i class="fa fa-globe"></i> {{tr "Datastore"}}
+        </legend>
+        <div class="provision_ds_selector" data-tab-content></div>
+      </fieldset>
+    </div>
+  </div>
 </form>
\ No newline at end of file
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/secgroups-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/secgroups-tab.js
@@ -48,7 +48,9 @@ define(function(require) {
     parentTab: "network-top-tab",
     listHeader: Locale.tr("Security Groups"),
     infoHeader: Locale.tr("Security Group"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_secgroups"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'SecurityGroup',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/secgroups-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/secgroups-tab/datatable.js
@@ -78,6 +78,8 @@ define(function(require) {
       "you_selected_multiple": Locale.tr("You selected the following security groups:")
     };
 
+    this.totalSecGroups = 0;
+
     this.conf.searchDropdownHTML = SearchDropdown({tableId: this.dataTableId});
     this.searchColumn = SEARCH_COLUMN;
 
@@ -87,6 +89,8 @@ define(function(require) {
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -96,6 +100,7 @@ define(function(require) {
 
   function _elementArray(element_json) {
     var element = element_json[XML_ROOT];
+    this.totalSecGroups++;
 
     var search = {
       NAME:  element.NAME,
@@ -115,4 +120,12 @@ define(function(require) {
         btoa(unescape(encodeURIComponent(JSON.stringify(search))))
     ];
   }
+
+  function _preUpdateView() {
+    this.totalSecGroups = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_secgroups").text(this.totalSecGroups);
+  }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab.js
@@ -50,7 +50,9 @@ define(function(require) {
     parentTab: "templates-top-tab",
     listHeader: Locale.tr("VM Templates"),
     infoHeader: Locale.tr("VM Template"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_templates"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'Template',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/datatable-common.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/datatable-common.js
@@ -58,7 +58,8 @@ define(function(require) {
           {"bSortable": false, "aTargets": ["check"]},
           {"sWidth": "35px", "aTargets": [0]},
           {"bVisible": true, "aTargets": SunstoneConfig.tabTableColumns(tabId)},
-          {"bVisible": false, "aTargets": ['_all']}
+          {"bVisible": false, "aTargets": ['_all']},
+          {"sType": "date-euro", "aTargets": [ 5 ]}
       ]
     }
 
@@ -118,7 +119,7 @@ define(function(require) {
         element.NAME,
         element.UNAME,
         element.GNAME,
-        Humanize.prettyTime(element.REGTIME),
+        Humanize.prettyTimeDatatable(element.REGTIME),
         (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||''),
         btoa(unescape(encodeURIComponent(JSON.stringify(search))))
     ];
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/datatable.js
@@ -34,11 +34,14 @@ define(function(require) {
 
   function Table(dataTableId, conf) {
     CommonDataTable.call(this, RESOURCE, TAB_NAME, dataTableId, conf);
+    this.totalTemplates = 0;
   };
 
   Table.prototype = Object.create(CommonDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -55,6 +58,16 @@ define(function(require) {
       return false;
     }
 
+    this.totalTemplates++;
+
     return this.elementArrayCommon(element_json);
   }
+
+  function _preUpdateView() {
+    this.totalTemplates = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_templates").text(this.totalTemplates);
+  }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create-common.js
@@ -43,6 +43,7 @@ define(function(require) {
     require('./create/wizard-tabs/network'),
     require('./create/wizard-tabs/os'),
     require('./create/wizard-tabs/io'),
+    require('./create/wizard-tabs/actions'),
     require('./create/wizard-tabs/context'),
     require('./create/wizard-tabs/scheduling'),
     require('./create/wizard-tabs/hybrid'),
--- /dev/null
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/actions.js
@@ -0,0 +1,224 @@
+/* -------------------------------------------------------------------------- */
+/* Copyright 2002-2017, OpenNebula Project, OpenNebula Systems                */
+/*                                                                            */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
+/* not use this file except in compliance with the License. You may obtain    */
+/* a copy of the License at                                                   */
+/*                                                                            */
+/* http://www.apache.org/licenses/LICENSE-2.0                                 */
+/*                                                                            */
+/* Unless required by applicable law or agreed to in writing, software        */
+/* distributed under the License is distributed on an "AS IS" BASIS,          */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
+/* See the License for the specific language governing permissions and        */
+/* limitations under the License.                                             */
+/* -------------------------------------------------------------------------- */
+
+define(function(require) {
+  /*
+    DEPENDENCIES
+   */
+
+  var Config = require('sunstone-config');
+  var Locale = require('utils/locale');
+  var Tips = require('utils/tips');
+  var WizardFields = require('utils/wizard-fields');
+  var UniqueId = require('utils/unique-id');
+  var Humanize = require('utils/humanize');
+  var TemplateUtils = require('utils/template-utils');
+
+  var TemplateHTML = require('hbs!./actions/html');
+  /*
+    CONSTANTS
+   */
+
+  var WIZARD_TAB_ID = require('./actions/wizardTabId');
+
+  /*
+    CONSTRUCTOR
+   */
+
+  function WizardTab(opts) {
+    if (!Config.isTemplateCreationTabEnabled(opts.tabId, 'actions')) {
+      throw "Wizard Tab not enabled";
+    }
+
+    this.wizardTabId = WIZARD_TAB_ID + UniqueId.id();
+    this.icon = "fa-calendar";
+    this.title = Locale.tr("Actions");
+  }
+
+  WizardTab.prototype.constructor = WizardTab;
+  WizardTab.prototype.html = _html;
+  WizardTab.prototype.setup = _setup;
+  WizardTab.prototype.onShow = _onShow;
+  WizardTab.prototype.retrieve = _retrieve;
+  WizardTab.prototype.fill = _fill;
+
+  return WizardTab;
+
+  function _html() {
+    return TemplateHTML();
+  }
+
+  function _onShow(context, panelForm) {
+  }
+
+  function _setup(context) {
+    var that = this;
+		
+    context.off('click', '#add_scheduling_temp_action');
+    context.on('click', '#add_scheduling_temp_action', function() {
+      $("#add_scheduling_temp_action", context).attr("disabled", "disabled");
+      $("#scheduling_temp_actions_table").append('<tr>\
+          <td>\
+            <select id="select_new_action" class="select_new_action" name="select_action">\
+              <option value="terminate">' + Locale.tr("terminate") + '</option>\
+              <option value="terminate-hard">' + Locale.tr("terminate-hard") + '</option>\
+              <option value="hold">' + Locale.tr("hold") + '</option>\
+              <option value="release">' + Locale.tr("release") + '</option>\
+              <option value="stop">' + Locale.tr("stop") + '</option>\
+              <option value="suspend">' + Locale.tr("suspend") + '</option>\
+              <option value="resume">' + Locale.tr("resume") + '</option>\
+              <option value="reboot">' + Locale.tr("reboot") + '</option>\
+              <option value="reboot-hard">' + Locale.tr("reboot-hard") + '</option>\
+              <option value="poweroff">' + Locale.tr("poweroff") + '</option>\
+              <option value="poweroff-hard">' + Locale.tr("poweroff-hard") + '</option>\
+              <option value="undeploy">' + Locale.tr("undeploy") + '</option>\
+              <option value="undeploy-hard">' + Locale.tr("undeploy-hard") + '</option>\
+              <option value="snapshot-create">' + Locale.tr("snapshot-create") + '</option>\
+            </select>\
+          </td>\
+         <td>\
+            <input id="date_input" type="date" placeholder="2013/12/30"/>\
+            <input id="time_input" type="time" placeholder="12:30"/>\
+         </td>\
+         <td>\
+            <button id="add_temp_action_json" class="secondary small button radius" >' + Locale.tr("Add") + '</button>\
+         </td>\
+         <td colspan=2></td>\
+       </tr>');
+
+      return false;
+    });
+
+    context.off("click", "#add_temp_action_json");
+    context.on("click" , "#add_temp_action_json", function(){
+      var date_input_value = $("#date_input", context).val();
+      var time_input_value = $("#time_input", context).val();
+
+      if (date_input_value == "" || time_input_value == ""){
+        return false;
+      }
+
+      var time_value = date_input_value + ' ' + time_input_value;
+      var epoch_str = new Date(time_value);
+      var time = parseInt(epoch_str.getTime()) / 1000;
+
+      var new_action = $("#select_new_action", context).val();
+      var sched_action = {};
+      sched_action.ACTION = new_action;
+      sched_action.TIME = time;
+
+      $(this).parents('tr').remove();
+      $("#add_scheduling_temp_action", context).removeAttr("disabled");
+
+      $("#sched_temp_actions_body").append(fromJSONtoActionsTable(sched_action));
+			
+      return false;
+    });
+
+    context.on("focusout" , "#time_input", function(){
+      $("#time_input").removeAttr("data-invalid");
+      $("#time_input").removeAttr("class");
+    });
+
+    context.off("click", ".remove_action_x");
+    context.on("click", ".remove_action_x", function(){
+      $(this).parents('tr').remove();
+    });
+  }
+
+  function _retrieve(context) {
+    var templateJSON = {};
+    var actionsJSON = [];
+
+    $("#scheduling_temp_actions_table tbody tr").each(function(index){
+      var first = $(this).children("td")[0];
+      if(!$('select', first).html()){
+        var actionJSON = {};
+        actionJSON.ID = index;
+        $(this).children("td").each(function(index2){
+          if(index2 == 0)
+            actionJSON.ACTION = $(this).text();
+          else if (index2 == 1){
+            var pretty_time = $(this).text();
+            pretty_time = pretty_time.split(' ');
+            var date = convertDate(pretty_time[1]);
+            var time_value = date + ' ' + pretty_time[0];
+            var epoch_str = new Date(time_value);
+            var time = parseInt(epoch_str.getTime()) / 1000;
+            actionJSON.TIME = time;
+          }
+        });
+      }
+      if (!$.isEmptyObject(actionJSON)) {actionsJSON.push(actionJSON)};
+    });
+
+    templateJSON['SCHED_ACTION'] = actionsJSON;
+    return templateJSON;
+  }
+
+  function _fill(context, templateJSON) {
+    var actions = fromJSONtoActionsTable(templateJSON.SCHED_ACTION);
+    $("#sched_temp_actions_body").append(actions);
+    delete templateJSON['SCHED_ACTION'];
+  }
+
+  function fromJSONtoActionsTable(actions_array) {
+    var str = ""
+
+    if (!actions_array) {
+      return "";
+    }
+
+    if (!$.isArray(actions_array)) {
+      var tmp_array = new Array();
+      tmp_array[0]  = actions_array;
+      actions_array = tmp_array;
+    }
+
+    if (!actions_array.length) {
+      return "";
+    }
+
+    $.each(actions_array, function(index, scheduling_action) {
+      str += fromJSONtoActionRow(scheduling_action);
+    });
+
+    return str;
+  }
+
+  function fromJSONtoActionRow(scheduling_action) {
+    var time_str = Humanize.prettyTime(scheduling_action.TIME);
+
+    var str = "";
+    str += '<tr class="tr_action">\
+       <td class="action_row">' + TemplateUtils.htmlEncode(scheduling_action.ACTION) + '</td>\
+       <td nowrap class="time_row">' + time_str + '</td>\
+       <td>\
+         <div>\
+           <a id="minus" class="remove_action_x" href="#"><i class="fa fa-trash-o"/></a>\
+         </div>\
+       </td>\
+     </tr>';
+
+    return str;
+  }
+
+  function convertDate(date_string){
+    date_string = date_string.split('/');
+    return date_string[2] + "-" + date_string[1] + "-" + date_string[0]; 
+  }
+
+});
--- /dev/null
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/actions/html.hbs
@@ -0,0 +1,15 @@
+<div class="row">
+  <div class="large-12 columns">
+    <table id="scheduling_temp_actions_table" class="info_table dataTable">
+      <thead>
+        <tr>
+          <th> {{tr "Action"}} </th>
+          <th> {{tr "Time"}} </th>
+          <th colspan=""> {{tr "Actions"}} </th>
+          <th><button id="add_scheduling_temp_action" class="button small success right radius"> {{tr "Add action"}} </button></th>
+        </tr>
+      </thead>
+      <tbody id="sched_temp_actions_body"></tbody>
+    </table>
+  </div>
+</div>
--- /dev/null
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/actions/wizardTabId.js
@@ -0,0 +1,19 @@
+/* -------------------------------------------------------------------------- */
+/* Copyright 2002-2017, OpenNebula Project, OpenNebula Systems                */
+/*                                                                            */
+/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
+/* not use this file except in compliance with the License. You may obtain    */
+/* a copy of the License at                                                   */
+/*                                                                            */
+/* http://www.apache.org/licenses/LICENSE-2.0                                 */
+/*                                                                            */
+/* Unless required by applicable law or agreed to in writing, software        */
+/* distributed under the License is distributed on an "AS IS" BASIS,          */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
+/* See the License for the specific language governing permissions and        */
+/* limitations under the License.                                             */
+/* -------------------------------------------------------------------------- */
+
+define(function(require){
+  return 'actionsTab';
+});
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/context.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/context.js
@@ -323,9 +323,10 @@ define(function(require) {
           OpenNebula.Image.list({
             timeout: true,
             success: function(request, obj_files){
-              while (match = file_ds_regexp.exec(value)) {
+
+              while (match = file_ds_regexp.exec(value.replace(/"/g, ""))) {
                 $.each(obj_files, function(key, value){
-                  if(value.IMAGE.NAME == match[1] && value.IMAGE.UNAME == match[2]){
+                  if(value.IMAGE.NAME.replace(/"/g, "") == match[1] && value.IMAGE.UNAME == match[2]){
                     files.push(value.IMAGE.ID);
                     return false;
                   }
@@ -357,18 +358,21 @@ define(function(require) {
   function _generateContextFiles(context) {
     var req_string=[];
     var selected_files = this.contextFilesTable.retrieveResourceTableSelect();
-
-    $.each(selected_files, function(index, fileId) {
-      OpenNebula.Image.show({
-        timeout: true,
-        data : {
-          id: fileId
-        },
-        success: function(request, obj_file){
-          req_string.push("$FILE[IMAGE=" + obj_file.IMAGE.NAME + ", IMAGE_UNAME=" + obj_file.IMAGE.UNAME + "]");
-          $('.FILES_DS', context).val(req_string.join(" "));
-        }
+    if(selected_files.length != 0){
+      $.each(selected_files, function(index, fileId) {
+        OpenNebula.Image.show({
+          timeout: true,
+          data : {
+            id: fileId
+          },
+          success: function(request, obj_file){
+            req_string.push("$FILE[IMAGE=" + '"' + obj_file.IMAGE.NAME + '"' + ", IMAGE_UNAME=" + obj_file.IMAGE.UNAME + "]");
+            $('.FILES_DS', context).val(req_string.join(" "));
+          }
+        });
       });
-    });
+    } else {
+      $('.FILES_DS', context).val("");
+    }
   };
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/capacity-create.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/capacity-create.js
@@ -84,8 +84,17 @@ define(function(require) {
   }
 
   function _totalCost(){
-    var total = document.getElementById('real_memory_cost').value + document.getElementById('real_cpu_cost').value;
-    document.getElementById('total_cost').textContent = "Total: "+ convertCostNumber(total);
+    var memory = document.getElementById('real_memory_cost').value;
+    var cpu = document.getElementById('real_cpu_cost').value;
+    if(memory === undefined && cpu === undefined){
+      document.getElementById('total_cost').textContent = "Total: 0.00";
+    } else if(memory === undefined){
+      document.getElementById('total_cost').textContent = "Total: " + convertCostNumber(cpu);
+    } else if(cpu === undefined){
+      document.getElementById('total_cost').textContent = "Total: " + convertCostNumber(memory);
+    } else {
+      document.getElementById('total_cost').textContent = "Total: " + convertCostNumber(memory + cpu);
+    }
   }
 
   function _calculatedRealMemory(){
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/general/html.hbs
@@ -119,7 +119,7 @@
       <legend>
         {{tr "Cost"}}
         <span>
-          <span id="total_cost">0.00</span>
+          <span id="total_cost"></span>
           <small>{{tr "COST"}} / {{tr "MONTH"}}</small>
         </span>
       </legend>
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/scheduling.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/create/wizard-tabs/scheduling.js
@@ -129,6 +129,7 @@ define(function(require) {
     that.clustersTable.initialize(selectOptions);
     that.clustersTable.refreshResourceTableSelect();
     that.datastoresTable.initialize(selectOptions);
+    that.datastoresTable.filter("system", 10);
     that.datastoresTable.refreshResourceTableSelect();
   }
 
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate.js
@@ -29,6 +29,7 @@ define(function(require) {
   var Tips = require('utils/tips');
   var UserInputs = require('utils/user-inputs');
   var WizardFields = require('utils/wizard-fields');
+  var TemplateUtils = require('utils/template-utils');
   var DisksResize = require('utils/disks-resize');
   var NicsSection = require('utils/nics-section');
   var VMGroupSection = require('utils/vmgroup-section');
@@ -36,6 +37,7 @@ define(function(require) {
   var CapacityInputs = require('tabs/templates-tab/form-panels/create/wizard-tabs/general/capacity-inputs');
   var Config = require('sunstone-config');
   var HostsTable = require('tabs/hosts-tab/datatable');
+  var DatastoresTable = require('tabs/datastores-tab/datatable');
 
   /*
     CONSTANTS
@@ -182,6 +184,11 @@ define(function(require) {
         tmp_json.SCHED_REQUIREMENTS = sched;
       }
 
+      var sched_ds = WizardFields.retrieveInput($("#SCHED_DS_REQUIREMENTS"  + template_id, context));
+      if(sched_ds){
+        tmp_json.SCHED_DS_REQUIREMENTS = sched_ds;
+      }
+
       var nics = [];
       var pcis = [];
 
@@ -266,6 +273,7 @@ define(function(require) {
         timeout: true,
         success: function (request, template_json) {
           that.template_objects.push(template_json);
+
           var options = {
             'select': true,
             'selectOptions': {
@@ -274,26 +282,68 @@ define(function(require) {
           }
 
           that.hostsTable = new HostsTable('HostsTable' + template_json.VMTEMPLATE.ID, options);
+          that.datastoresTable = new DatastoresTable('DatastoresTable' + template_json.VMTEMPLATE.ID, options);
+
           templatesContext.append(
             TemplateRowHTML(
               { element: template_json.VMTEMPLATE,
                 capacityInputsHTML: CapacityInputs.html(),
-                hostsDatatable: that.hostsTable.dataTableHTML
+                hostsDatatable: that.hostsTable.dataTableHTML,
+                dsDatatable: that.datastoresTable.dataTableHTML
               }) );
 
           $(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable", that.hostsTable);
+          $(".provision_ds_selector" + template_json.VMTEMPLATE.ID, context).data("dsTable", that.datastoresTable);
+
           var selectOptions = {
             'selectOptions': {
               'select_callback': function(aData, options) {
-                generateRequirements($(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable"), context, template_json.VMTEMPLATE.ID);
+                var hostTable = $(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable");
+                var dsTable = $(".provision_ds_selector" + template_json.VMTEMPLATE.ID, context).data("dsTable");
+                generateRequirements(hostTable, dsTable, context, template_json.VMTEMPLATE.ID);
               },
               'unselect_callback': function(aData, options) {
-                generateRequirements($(".provision_host_selector"+ template_json.VMTEMPLATE.ID, context).data("hostsTable"), context, template_json.VMTEMPLATE.ID);
-              }
+                var hostTable = $(".provision_host_selector" + template_json.VMTEMPLATE.ID, context).data("hostsTable");
+                var dsTable = $(".provision_ds_selector" + template_json.VMTEMPLATE.ID, context).data("dsTable");
+                generateRequirements(hostTable, dsTable, context, template_json.VMTEMPLATE.ID);
+               }
             }
           }
           that.hostsTable.initialize(selectOptions);
           that.hostsTable.refreshResourceTableSelect();
+          that.datastoresTable.initialize(selectOptions);
+          that.datastoresTable.filter("system", 10);
+          that.datastoresTable.refreshResourceTableSelect();
+
+          var reqJSON = template_json.VMTEMPLATE.TEMPLATE.SCHED_REQUIREMENTS;
+          if (reqJSON) {
+            $('#SCHED_REQUIREMENTS' + template_json.VMTEMPLATE.ID, context).val(reqJSON);
+            var req = TemplateUtils.escapeDoubleQuotes(reqJSON);
+            var host_id_regexp = /(\s|\||\b)ID=\\"([0-9]+)\\"/g;
+            var hosts = [];
+            while (match = host_id_regexp.exec(req)) {
+                hosts.push(match[2]);
+            }
+            var selectedResources = {
+              ids : hosts
+            }
+            that.hostsTable.selectResourceTableSelect(selectedResources);
+          }
+
+          var dsReqJSON = template_json.VMTEMPLATE.TEMPLATE.SCHED_DS_REQUIREMENTS;
+          if (dsReqJSON) {
+            $('#SCHED_DS_REQUIREMENTS' + template_json.VMTEMPLATE.ID, context).val(dsReqJSON);
+            var dsReq = TemplateUtils.escapeDoubleQuotes(dsReqJSON);
+            var ds_id_regexp = /(\s|\||\b)ID=\\"([0-9]+)\\"/g;
+            var ds = [];
+            while (match = ds_id_regexp.exec(dsReq)) {
+              ds.push(match[2]);
+            }
+            var selectedResources = {
+              ids : ds
+            }
+            that.datastoresTable.selectResourceTableSelect(selectedResources);
+          }
 
           DisksResize.insert({
             template_json: template_json,
@@ -383,21 +433,22 @@ define(function(require) {
     Tips.setup(context);
     return false;
   }
-  function generateRequirements(hosts_table, context, id) {
+
+  function generateRequirements(hosts_table, ds_table, context, id) {
       var req_string=[];
-      //var req_ds_string=[];
+      var req_ds_string=[];
       var selected_hosts = hosts_table.retrieveResourceTableSelect();
-      //var selected_ds = this.datastoresTable.retrieveResourceTableSelect();
+      var selected_ds = ds_table.retrieveResourceTableSelect();
 
       $.each(selected_hosts, function(index, hostId) {
         req_string.push('ID="'+hostId+'"');
       });
 
-      /*$.each(selected_ds, function(index, dsId) {
+      $.each(selected_ds, function(index, dsId) {
         req_ds_string.push('ID="'+dsId+'"');
-      });*/
+      });
 
       $('#SCHED_REQUIREMENTS' + id, context).val(req_string.join(" | "));
-      //$('#SCHED_DS_REQUIREMENTS', context).val(req_ds_string.join(" | "));
+      $('#SCHED_DS_REQUIREMENTS' + id, context).val(req_ds_string.join(" | "));
   };
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate/templateRow.hbs
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/templates-tab/form-panels/instantiate/templateRow.hbs
@@ -67,6 +67,7 @@
       </fieldset>
     </div>
   </div>
+  {{#isFeatureEnabled "show_host_instantiate"}}
   <div class="row">
     <div class="small-12 columns hostContext{{element.ID}}">
       <fieldset>
@@ -86,7 +87,29 @@
       </fieldset>
     </div>
   </div>
-   <div class="row">
+  {{/isFeatureEnabled}}
+  {{#isFeatureEnabled "show_ds_instantiate"}}
+    <div class="row">
+      <div class="small-12 columns dsContext{{element.ID}}">
+        <fieldset>
+          <legend>
+            <i class="fa fa-globe"></i> {{tr "Datastore"}}
+          </legend>
+          <div class="provision_ds_selector{{element.ID}}" data-tab-content>{{{dsDatatable}}}</div>
+          <div class="row">
+              <div class="large-12 columns">
+                <label for="SCHED_DS_REQUIREMENTS">
+                  {{tr "Expression"}}
+                  {{{tip (tr "Boolean expression that rules out entries from the pool of datastores suitable to run this VM.")}}}
+                </label>
+                <input type="text" wizard_field="SCHED_DS_REQUIREMENTS" id="SCHED_DS_REQUIREMENTS{{element.ID}}" name="requirements" />
+              </div>
+          </div>
+        </fieldset>
+      </div>
+    </div>
+  {{/isFeatureEnabled}}
+  <div class="row">
     <div class="medium-6 small-12 columns vcenterVMFolderContext{{element.ID}}">
       <div class="provision_vcenter_vm_folder_selector">
       </div>
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vmgroup-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vmgroup-tab.js
@@ -42,7 +42,8 @@ define(function(require) {
     infoHeader: Locale.tr("VM Groups"),
     subheader: '<span>\
         <span class="total_vmgroup"/> <small>'+Locale.tr("TOTAL")+'</small>\
-      </span>',
+        </small>&emsp;\
+        <span class="total_vms_vmgroup"/> <small>'+Locale.tr("TOTAL VMs")+'</small></span>',
     resource: 'VMGroup',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vmgroup-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vmgroup-tab/datatable.js
@@ -80,6 +80,8 @@ define(function(require) {
       "you_selected_multiple": Locale.tr("You selected the following vm groups:")
     };
 
+    this.totalVMGroups = 0;
+    this.totalVMs = 0;
 
     this.conf.searchDropdownHTML = SearchDropdown({tableId: this.dataTableId});
     this.searchColumn = SEARCH_COLUMN;
@@ -90,6 +92,8 @@ define(function(require) {
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -100,6 +104,7 @@ define(function(require) {
   function _elementArray(element_json) {
     var element = element_json[XML_ROOT];
     var numVms = 0;
+    this.totalVMGroups++;
 
     for(role_index in element.ROLES.ROLE){
       if(element.ROLES.ROLE[role_index].VMS){
@@ -108,6 +113,7 @@ define(function(require) {
         numVms += vms.length;
       }
     }
+    this.totalVMs += numVms;
 
     var search = {
       NAME:  element.NAME,
@@ -129,4 +135,14 @@ define(function(require) {
     ];
   }
 
+  function _preUpdateView() {
+    this.totalVMGroups = 0;
+    this.totalVMs= 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_vmgroup").text(this.totalVMGroups);
+    $(".total_vms_vmgroup").text(this.totalVMs);
+  }
+
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vmgroup-tab/utils/role-tab/html.hbs
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vmgroup-tab/utils/role-tab/html.hbs
@@ -33,7 +33,7 @@
       </span>
       <div style="margin-left: 30px; margin-bottom:5px;">
         <input type="radio" name="protocol_{{idRole}}" value="NONE" checked><label>{{tr "None"}}</label></br>
-        <input type="radio" name="protocol_{{idRole}}" value="AFFINED""><label>{{tr "Affined"}}</label></br>
+        <input type="radio" name="protocol_{{idRole}}" value="AFFINED"><label>{{tr "Affined"}}</label></br>
         <input type="radio" name="protocol_{{idRole}}" value="ANTI_AFFINED"><label>{{tr "Anti Affined"}}</label>
       </div>
     </label>
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vms-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vms-tab/datatable.js
@@ -60,6 +60,7 @@ define(function(require) {
       "bDeferRender": true,
       "aoColumnDefs": [
           {"sType": "ip-address", "aTargets": [0]},
+          {"sType": "num", "aTargets": [1]},
           {"bSortable": false, "aTargets": ["check", 6, 7, 11]},
           {"sWidth": "35px", "aTargets": [0]},
           {"bVisible": true, "aTargets": SunstoneConfig.tabTableColumns(TAB_NAME)},
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vms-tab/panels/log.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vms-tab/panels/log.js
@@ -59,7 +59,7 @@ define(function(require) {
 
   function _html() {
     return '<div class="row">' +
-      '<div class="large-12 columns vm_log_container monospace">' +
+      '<div class="large-12 columns vm_log_container monospace" style="overflow: auto; height: 500px">' +
         '<div class="text-center" style="height: 100px;">' +
           '<span style="font-size:80px">' +
             '<i class="fa fa-spinner fa-spin"></i>' +
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vnets-topology-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vnets-topology-tab.js
@@ -588,7 +588,9 @@ define(function(require) {
       _network.cluster(clusterOptionsByData);
     });
 
-    _network.stabilize();
+    if(_network){
+      _network.stabilize();
+    }
   }
 
   function _openVMs(){
@@ -604,10 +606,15 @@ define(function(require) {
       }
     });
 
-    _network.stabilize();
+    if(_network){
+      _network.stabilize();
+    }
   }
 
   function _fit(){
-    _network.fit();
+
+    if(_network){
+      _network.fit();
+    }
   }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vrouter-templates-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vrouter-templates-tab.js
@@ -48,7 +48,9 @@ define(function(require) {
     parentTab: "templates-top-tab",
     listHeader: Locale.tr("Virtual Router VM Templates"),
     infoHeader: Locale.tr("Virtual Router VM Template"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_vrouters"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'VirtualRouterTemplate',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vrouter-templates-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vrouter-templates-tab/datatable.js
@@ -34,11 +34,14 @@ define(function(require) {
 
   function Table(dataTableId, conf) {
     CommonDataTable.call(this, RESOURCE, TAB_NAME, dataTableId, conf);
+    this.totalVRouters = 0;
   };
 
   Table.prototype = Object.create(CommonDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -55,6 +58,16 @@ define(function(require) {
       return false;
     }
 
+    this.totalVRouters++;
+
     return this.elementArrayCommon(element_json);
   }
+
+  function _preUpdateView() {
+    this.totalVRouters = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_vrouters").text(this.totalVRouters);
+  }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vrouters-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vrouters-tab.js
@@ -49,7 +49,9 @@ define(function(require) {
     parentTab: "instances-top-tab",
     listHeader: Locale.tr("Virtual Routers"),
     infoHeader: Locale.tr("Virtual Router"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_routers"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'VirtualRouter',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/vrouters-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/vrouters-tab/datatable.js
@@ -78,6 +78,8 @@ define(function(require) {
       "you_selected_multiple": Locale.tr("You selected the following virtual routers:")
     };
 
+    this.totalRouters = 0;
+
     this.conf.searchDropdownHTML = SearchDropdown({tableId: this.dataTableId});
     this.searchColumn = SEARCH_COLUMN;
 
@@ -87,6 +89,8 @@ define(function(require) {
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -96,6 +100,7 @@ define(function(require) {
 
   function _elementArray(element_json) {
     var element = element_json[XML_ROOT];
+    this.totalRouters++;
 
     var search = {
       NAME:  element.NAME,
@@ -115,4 +120,12 @@ define(function(require) {
         btoa(unescape(encodeURIComponent(JSON.stringify(search))))
     ];
   }
+
+  function _preUpdateView() {
+    this.totalRouters = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_routers").text(this.totalRouters);
+  }
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/zones-tab.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/zones-tab.js
@@ -43,7 +43,9 @@ define(function(require) {
     parentTab: "infrastructure-top-tab",
     listHeader: Locale.tr("Zones"),
     infoHeader: Locale.tr("Zone"),
-    subheader: '',
+    subheader: '<span>\
+        <span class="total_zones"/> <small>'+Locale.tr("TOTAL")+'</small>\
+      </span>',
     resource: 'Zone',
     buttons: Buttons,
     actions: Actions,
--- opennebula-5.4.0.orig/src/sunstone/public/app/tabs/zones-tab/datatable.js
+++ opennebula-5.4.0/src/sunstone/public/app/tabs/zones-tab/datatable.js
@@ -74,12 +74,16 @@ define(function(require) {
       "you_selected_multiple": Locale.tr("You selected the following Zones:")
     };
 
+    this.totalZones = 0;
+
     TabDataTable.call(this);
   };
 
   Table.prototype = Object.create(TabDataTable.prototype);
   Table.prototype.constructor = Table;
   Table.prototype.elementArray = _elementArray;
+  Table.prototype.preUpdateView = _preUpdateView;
+  Table.prototype.postUpdateView = _postUpdateView;
 
   return Table;
 
@@ -89,6 +93,7 @@ define(function(require) {
 
   function _elementArray(element_json) {
     var element = element_json.ZONE;
+    this.totalZones++;
 
     return [
         '<input class="check_item" type="checkbox" id="' + RESOURCE.toLowerCase() + '_' +
@@ -100,4 +105,13 @@ define(function(require) {
         (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'')
     ];
   }
+
+  function _preUpdateView() {
+    this.totalZones = 0;
+  }
+
+  function _postUpdateView() {
+    $(".total_zones").text(this.totalZones);
+  }
+
 });
--- opennebula-5.4.0.orig/src/sunstone/public/app/utils/humanize.js
+++ opennebula-5.4.0/src/sunstone/public/app/utils/humanize.js
@@ -32,7 +32,8 @@ define(function(require) {
     'prettyTime': _prettyTime,
     'prettyTimeAxis': _prettyTimeAxis,
     'prettyPrintJSON': _prettyPrintJSON,
-    'prettyTimeAgo': _format_date
+    'prettyTimeAgo': _format_date,
+    'prettyTimeDatatable': _prettyTimeDatatable
   }
 
   /*
@@ -240,6 +241,20 @@ define(function(require) {
     return str;
   }
 
+  function _prettyTimeDatatable(seconds) {
+    var d = new Date();
+    d.setTime(seconds * 1000);
+
+    var secs = _pad(d.getSeconds(), 2);
+    var hour = _pad(d.getHours(), 2);
+    var mins = _pad(d.getMinutes(), 2);
+    var day = _pad(d.getDate(), 2);
+    var month = _pad(d.getMonth() + 1, 2); //getMonths returns 0-11
+    var year = d.getFullYear();
+
+    return day + "/" + month + "/" + year + " " + hour + ":" + mins + ":" + secs;
+  }
+
   function _format_date(unix_timestamp) {
     var difference_in_seconds = (Math.round((new Date()).getTime() / 1000)) - unix_timestamp,
         current_date = new Date(unix_timestamp * 1000), minutes, hours;
--- opennebula-5.4.0.orig/src/sunstone/public/app/utils/user-inputs.js
+++ opennebula-5.4.0/src/sunstone/public/app/utils/user-inputs.js
@@ -87,7 +87,7 @@ define(function(require) {
     var order_inputs = "";
 
     $('.user_input_attrs tbody tr').each(function(key, value){
-      order_inputs += $(".user_input_name", $(this)).val() + ",";
+      order_inputs += $(".user_input_name", $(this)).val().toUpperCase() + ",";
     });
 
     this.order = order_inputs.slice(0,-1);
--- opennebula-5.4.0.orig/src/vm_template/VMTemplate.cc
+++ opennebula-5.4.0/src/vm_template/VMTemplate.cc
@@ -74,13 +74,16 @@ int VMTemplate::insert(SqlDB *db, string
     // ---------------------------------------------------------------------
     // Check default attributes
     // ---------------------------------------------------------------------
-
     erase_template_attribute("NAME", name);
 
+    // ---------------------------------------------------------------------
+    // Remove DONE/MESSAGE from SCHED_ACTION
+    // ---------------------------------------------------------------------
+    parse_sched_action();
+
     // ------------------------------------------------------------------------
     // Insert the Template
     // ------------------------------------------------------------------------
-
     return insert_replace(db, false, error_str);
 }
 
@@ -167,6 +170,30 @@ error_common:
     return -1;
 }
 
+void VMTemplate::parse_sched_action()
+{
+    vector<VectorAttribute *> _sched_actions;
+    vector<VectorAttribute *>::iterator i;
+
+    get_template_attribute("SCHED_ACTION", _sched_actions);
+
+    for ( i = _sched_actions.begin(); i != _sched_actions.end() ; ++i)
+    {
+        (*i)->remove("DONE");
+        (*i)->remove("MESSAGE");
+    }
+}
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+int VMTemplate::post_update_template(string& error)
+{
+    parse_sched_action();
+
+    return 0;
+}
+
 /* ************************************************************************ */
 /* VMTemplate :: Misc                                                       */
 /* ************************************************************************ */
--- opennebula-5.4.0.orig/src/vmm_mad/exec/vmm_exec_kvm.conf
+++ opennebula-5.4.0/src/vmm_mad/exec/vmm_exec_kvm.conf
@@ -27,7 +27,7 @@
 #  - hyperv_options: options used for FEATURES = [ HYPERV = yes ]
 # NOTE: raw attribute value is appended to that on the VM template
 
-EMULATOR = /usr/bin/qemu-system-x86_64
+#EMULATOR = /usr/libexec/qemu-kvm
 
 #VCPU = 1
 
--- opennebula-5.4.0.orig/src/vmm_mad/remotes/az/az_driver.conf
+++ opennebula-5.4.0/src/vmm_mad/remotes/az/az_driver.conf
@@ -1,98 +1,4 @@
 proxy_uri:
-regions:
-    default:
-        region_name: "West Europe"
-    # pem_management_cert --> Absolute path to pem management certificate
-    # Info on creating certificates:
-    # http://azure.microsoft.com/en-us/documentation/articles/linux-use-ssh-key/
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small: 5
-            Medium: 1
-            Large: 0
-    west-europe:
-        region_name: "West Europe"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small: 5
-            Medium: 1
-            Large: 0
-    north-europe:
-        region_name: "North Europe"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
-    east-us:
-        region_name: "East US"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
-    south-central-us:
-        region_name: "South Central US"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
-    west-us:
-        region_name: "West US"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
-    east-asia:
-        region_name: "East Asia"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
-    southeast-asia:
-        region_name: "Southeast Asia"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
-    japan-west:
-        region_name: "Japan West"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
-    brazil-south:
-        region_name: "Brazil South"
-        pem_management_cert:
-        subscription_id:
-        management_endpoint:
-        capacity:
-            Small:
-            Medium:
-            Large:
 instance_types:
     ExtraSmall:
         cpu: 1
--- opennebula-5.4.0.orig/src/vmm_mad/remotes/az/az_driver.rb
+++ opennebula-5.4.0/src/vmm_mad/remotes/az/az_driver.rb
@@ -33,6 +33,7 @@ require 'yaml'
 require 'rubygems'
 require 'azure'
 require 'uri'
+require 'tempfile'
 
 $: << RUBY_LIB_LOCATION
 
@@ -135,6 +136,7 @@ class AzureDriver
     # Azure constructor, loads credentials and endpoint
     def initialize(host)
         @host = host
+        @to_inst ={}
 
         @public_cloud_az_conf  = YAML::load(File.read(AZ_DRIVER_CONF))
 
@@ -143,67 +145,115 @@ class AzureDriver
         end
 
         @instance_types = @public_cloud_az_conf['instance_types']
+        @instance_types.keys.each{ |key|
+            @to_inst[key.upcase] = key
+        }
+
+        certificate = Tempfile.new("certificate")
+        conn_opts = get_connect_info(host)
+
+        access_id     = conn_opts[:id]
+        endpoint_addr = conn_opts[:endpoint]
+        @region_name   = conn_opts[:region]
+        certificate << conn_opts[:cert]
 
-        regions = @public_cloud_az_conf['regions']
-        @region = regions[host] || regions["default"]
+        certificate.close
 
         # Sanitize region data
-        if @region['pem_management_cert'].nil?
+        if certificate.nil?
             raise "pem_management_cert not defined for #{host}"
         end
 
-        if @region['subscription_id'].nil?
+        if access_id.nil?
             raise "subscription_id not defined for #{host}"
         end
 
         # Set default endpoint if not declared
-        if @region['management_endpoint'].nil?
-           @region['management_endpoint']="https://management.core.windows.net"
+        if endpoint_addr.nil?
+            endpoint_addr="https://management.core.windows.net"
         end
+        ###################################################################
 
         Azure.configure do |config|
-          config.management_certificate = @region['pem_management_cert']
-          config.subscription_id        = @region['subscription_id']
-          config.management_endpoint    = @region['management_endpoint']
+          config.management_certificate = certificate.path
+          config.subscription_id        = access_id
+          config.management_endpoint    = endpoint_addr
         end
 
+		certificate.unlink    # deletes the temp file
+
         @azure_vms = Azure::VirtualMachineManagementService.new
     end
 
+    def get_host_info(client)
+        pool = OpenNebula::HostPool.new(client)
+        pool.info
+        objects=pool.select {|object| object.name==@host }
+
+        objects.first
+    end
+
+    # Check the current template to retrieve
+    # conection info needed for Azure
+    def get_connect_info(host)
+        conn_opts={}
+        client   = OpenNebula::Client.new
+        xmlhost = get_host_info(client)
+
+        system = OpenNebula::System.new(client)
+        config = system.get_configuration
+        raise "Error getting oned configuration : #{config.message}" if OpenNebula.is_error?(config)
+
+        token = config["ONE_KEY"]
+
+        conn_opts = {
+            :cert => xmlhost["TEMPLATE/AZ_CERT"],
+            :id   => xmlhost["TEMPLATE/AZ_ID"]
+        }
+        #conn_opts = OpenNebula.encrypt(conn_opts, token)
+        conn_opts = OpenNebula.decrypt(conn_opts, token)
+
+        conn_opts[:region] = xmlhost["TEMPLATE/REGION_NAME"]
+        conn_opts[:endpoint] = xmlhost["TEMPLATE/AZ_ENDPOINT"]
+
+
+        return conn_opts
+    end
+
     # DEPLOY action
     def deploy(id, host, xml_text, lcm_state, deploy_id)
-      if lcm_state == "BOOT" || lcm_state == "BOOT_FAILURE"
-        load_default_template_values
+        if lcm_state == "BOOT" || lcm_state == "BOOT_FAILURE"
+            load_default_template_values
 
-        az_info = get_deployment_info(host, xml_text)
+            az_info = get_deployment_info(host, xml_text)
 
-        if !az_value(az_info, 'IMAGE')
-            raise "Cannot find IMAGE in deployment file"
-        end
+            if !az_value(az_info, 'IMAGE')
+                raise "Cannot find IMAGE in deployment file"
+            end
 
-        csn = az_value(az_info, 'CLOUD_SERVICE')
+            csn = az_value(az_info, 'CLOUD_SERVICE')
 
-        csn = "csn#{id}" if !csn
+            csn = "csn#{id}" if !csn
 
-        create_params  = create_params(id,csn,az_info)
-        create_options = create_options(id,csn,az_info)
-        instance       = nil
+            create_params  = create_params(id,csn,az_info)
+            create_options = create_options(id,csn,az_info)
+            instance       = nil
 
-        in_silence do
-          instance = @azure_vms.create_virtual_machine(create_params,
-                                                       create_options)
-        end
+            in_silence do
+              instance = @azure_vms.create_virtual_machine(create_params,
+                                                           create_options)
+            end
 
 
-        if instance.class == Azure::VirtualMachineManagement::VirtualMachine
-            puts(instance.vm_name)
+            if instance.class == Azure::VirtualMachineManagement::VirtualMachine
+                puts(instance.vm_name)
+            else
+                raise "Deployment failure " + instance
+            end
         else
-            raise "Deployment failure " + instance
+            restore(deploy_id)
+            deploy_id
         end
-      else
-        restore(deploy_id)
-        deploy_id
-      end
     end
 
     # Shutdown an Azure instance
@@ -248,12 +298,19 @@ class AzureDriver
     def monitor_all_vms
         totalmemory = 0
         totalcpu    = 0
-        @region['capacity'].each { |name, size|
-            cpu, mem = instance_type_capacity(name)
 
-            totalmemory += mem * size.to_i
-            totalcpu    += cpu * size.to_i
-        }
+        host_obj=get_host_info(OpenNebula::Client.new)
+        capacity = host_obj.to_hash["HOST"]["TEMPLATE"]["CAPACITY"]
+        if !capacity.nil? && Hash === capacity
+            capacity.each{ |name, value|
+                cpu, mem = instance_type_capacity(name)
+
+                totalmemory += mem * value.to_i
+                totalcpu    += cpu * value.to_i
+            }
+        else
+            raise "you must define CAPACITY section properly! check the template"
+        end
 
         host_info =  "HYPERVISOR=AZURE\n"
         host_info << "PUBLIC_CLOUD=YES\n"
@@ -295,7 +352,7 @@ class AzureDriver
                 usedcpu    += cpu
                 usedmemory += mem
             end
-          rescue 
+          rescue
             next
           end
         end
@@ -314,9 +371,10 @@ private
     # Get the associated capacity of the instance_type as cpu (in 100 percent
     # e.g. 800 for 8 cores) and memory (in KB)
     def instance_type_capacity(name)
-        return 0, 0 if @instance_types[name].nil?
-        return (@instance_types[name]['cpu'].to_f * 100).to_i ,
-               (@instance_types[name]['memory'].to_f * 1024 * 1024).to_i
+        resource = @instance_types[@to_inst[name]] || @instance_types[name]
+        return 0, 0 if resource.nil?
+        return (resource['cpu'].to_f * 100).to_i ,
+               (resource['memory'].to_f * 1024 * 1024).to_i
     end
 
     # Get the Azure section of the template. If more than one Azure section
@@ -331,6 +389,7 @@ private
         # First, let's see if we have an Azure location that matches
         # our host name
         all_az_elements.each { |element|
+
             cloud_host = element.elements["LOCATION"]
             type       = element.elements["TYPE"].text
 
@@ -342,87 +401,84 @@ private
         }
 
         if !az
-              # If we don't find an Azure location, and ONE just
-              # knows about one Azure location, let's use that
-              if all_az_elements.size == 1 and
-                 all_az_elements[0].elements["TYPE"].text.downcase.eql? "azure"
-                  az = all_az_elements[0]
-              else
-                  STDERR.puts(
-                      "Cannot find Azure element in VM template "<<
-                      "or couldn't find any Azure location matching "<<
-                      "one of the templates.")
-                  exit(-1)
-              end
-          end
+            # If we don't find an Azure location, and ONE just
+            # knows about one Azure location, let's use that
+            if all_az_elements.size == 1 and
+                all_az_elements[0].elements["TYPE"].text.downcase.eql? "azure"
+                az = all_az_elements[0]
+            else
+                STDERR.puts(
+                "Cannot find Azure element in VM template "<<
+                "or couldn't find any Azure location matching "<<
+                "one of the templates.")
+                exit(-1)
+            end
+        end
 
-         # If LOCATION not explicitly defined, try to get default, if not
-          # try to use hostname as datacenter
-          if !az.elements["LOCATION"]
+        # location can be retrieved from host information...
+
+        # If LOCATION not explicitly defined, try to get default, if not
+        # try to use hostname as datacenter
+        if !az.elements["LOCATION"]
             location=REXML::Element.new("LOCATION")
-            if @defaults["LOCATION"]
-              location.text=@defaults["LOCATION"]
+            if @region_name
+                location.text=@region_name
             else
-              location.text=host
+                location.text=host
             end
             az.elements << location
-          end
-
-          # Translate region name form keyword to actual value
-          region_keyword = az.elements["LOCATION"].text
-          translated_region = @public_cloud_az_conf["regions"][region_keyword]
-          az.elements["LOCATION"].text=translated_region["region_name"]
+        end
 
-          az
+        az
     end
 
     # Retrive the vm information from the Azure instance
     def parse_poll(instance)
-      begin
-        info =  "#{POLL_ATTRIBUTE[:memory]}=0 " \
-                "#{POLL_ATTRIBUTE[:cpu]}=0 " \
-                "#{POLL_ATTRIBUTE[:nettx]}=0 " \
-                "#{POLL_ATTRIBUTE[:netrx]}=0 "
-
-        state = ""
-        if !instance
-            state = VM_STATE[:deleted]
-        else
-            state = case instance.deployment_status
-            when "Running", "Starting"
-                VM_STATE[:active]
-            when "Suspended", "Stopping",
-                VM_STATE[:paused]
+        begin
+            info =  "#{POLL_ATTRIBUTE[:memory]}=0 " \
+                    "#{POLL_ATTRIBUTE[:cpu]}=0 " \
+                    "#{POLL_ATTRIBUTE[:nettx]}=0 " \
+                    "#{POLL_ATTRIBUTE[:netrx]}=0 "
+
+            state = ""
+            if !instance
+                state = VM_STATE[:deleted]
             else
-                VM_STATE[:unknown]
-            end
-        end
-        info << "#{POLL_ATTRIBUTE[:state]}=#{state} "
-
-        AZ_POLL_ATTRS.map { |key|
-            value = instance.send(key)
-            if !value.nil? && !value.empty?
-                if key.to_s.upcase == "TCP_ENDPOINTS" or
-                   key.to_s.upcase == "UDP_ENDPOINTS"
-                    value_str = format_endpoints(value)
-                elsif value.kind_of?(Hash)
-                    value_str = value.inspect
+                state = case instance.deployment_status
+                when "Running", "Starting"
+                    VM_STATE[:active]
+                when "Suspended", "Stopping",
+                    VM_STATE[:paused]
                 else
-                    value_str = value
+                    VM_STATE[:unknown]
                 end
+            end
+            info << "#{POLL_ATTRIBUTE[:state]}=#{state} "
 
-                info << "AZ_#{key.to_s.upcase}="
-                info << "\\\"#{value_str.gsub("\"","")}\\\" "
+            AZ_POLL_ATTRS.map { |key|
+                value = instance.send(key)
+                if !value.nil? && !value.empty?
+                    if key.to_s.upcase == "TCP_ENDPOINTS" or
+                        key.to_s.upcase == "UDP_ENDPOINTS"
+                        value_str = format_endpoints(value)
+                    elsif value.kind_of?(Hash)
+                        value_str = value.inspect
+                    else
+                        value_str = value
+                    end
 
-            end
-        }
+                    info << "AZ_#{key.to_s.upcase}="
+                    info << "\\\"#{value_str.gsub("\"","")}\\\" "
 
-        info
-      rescue
-        # Unknown state if exception occurs retrieving information from
-        # an instance
-        "#{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:unknown]} "
-      end
+                end
+            }
+
+            info
+        rescue
+            # Unknown state if exception occurs retrieving information from
+            # an instance
+            "#{POLL_ATTRIBUTE[:state]}=#{VM_STATE[:unknown]} "
+        end
     end
 
     def format_endpoints(endpoints)
--- opennebula-5.4.0.orig/src/vmm_mad/remotes/ec2/ec2_driver.rb
+++ opennebula-5.4.0/src/vmm_mad/remotes/ec2/ec2_driver.rb
@@ -56,6 +56,8 @@ def handle_exception(action, ex, host, d
     id      ||= ""
     OpenNebula::log_error(action + " of VM #{id} #{did} on host #{host} #{file} "+
                 "due to \"#{ex.message}\"")
+    OpenNebula.error_message("There is a problem: #{ex.message}")
+
     STDERR.puts "********* STACK TRACE *********"
     STDERR.puts ex.backtrace
     STDERR.puts "*******************************"
--- opennebula-5.4.0.orig/src/vnm_mad/remotes/vxlan/vxlan_driver.rb
+++ opennebula-5.4.0/src/vnm_mad/remotes/vxlan/vxlan_driver.rb
@@ -51,7 +51,7 @@ class VXLANDriver < VNMMAD::VLANDriver
         end
 
         mc  = ipaddr.to_i + @nic[:vlan_id].to_i
-        mcs = VNMMAD::VNMNetwork::IPv4.to_s(mc)
+        mcs = IPAddr.new(mc, Socket::AF_INET).to_s
 
         mtu = @nic[:mtu] ? "mtu #{@nic[:mtu]}" : "mtu #{@nic[:conf][:vxlan_mtu]}"
         ttl = @nic[:conf][:vxlan_ttl] ? "ttl #{@nic[:conf][:vxlan_ttl]}" : ""
